// PhotosService.cs
// Facebook/Framework/Service
// Copyright (c) 2007, Nikhil Kothari. All Rights Reserved.
//

using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Text;
using Facebook.Service.Core;

namespace Facebook.Service {

    /// <summary>
    /// Represents the service APIs that allow accessing photo information.
    /// </summary>
    public sealed class PhotosService {

        private FacebookSession _session;

        internal PhotosService(FacebookSession session) {
            Debug.Assert(session != null);
            _session = session;
        }

        /// <summary>
        /// Gets the album identified by its ID.
        /// </summary>
        /// <param name="albumID">The unique ID of the album.</param>
        /// <returns>The album information for the specified album.</returns>
        public Album GetAlbum(string albumID) {
            if (String.IsNullOrEmpty("albumID")) {
                throw new ArgumentNullException("albumID");
            }

            ICollection<Album> albums = GetAlbums(null, new string[] { albumID });
            if ((albums != null) && (albums.Count != 0)) {
                foreach (Album album in albums) {
                    return album;
                }
            }

            return null;
        }

        /// <summary>
        /// Gets the albums identified by the specified IDs.
        /// </summary>
        /// <param name="albumIDs">The unique IDs of the albums.</param>
        /// <returns>The list of identified albums.</returns>
        public ICollection<Album> GetAlbums(ICollection<string> albumIDs) {
            if ((albumIDs == null) || (albumIDs.Count == 0)) {
                throw new ArgumentNullException("albumIDs");
            }

            return GetAlbums(null, albumIDs);
        }

        private ICollection<Album> GetAlbums(string userID, ICollection<string> albumIDs) {
            FacebookRequest request = new FacebookRequest(_session);
            if (String.IsNullOrEmpty(userID) == false) {
                request.Parameters["uid"] = userID;
            }
            if ((albumIDs != null) && (albumIDs.Count != 0)) {
                StringBuilder idListBuilder = new StringBuilder();
                foreach (string id in albumIDs) {
                    if (idListBuilder.Length != 0) {
                        idListBuilder.Append(",");
                    }
                    idListBuilder.Append(id);
                }
                request.Parameters["aids"] = idListBuilder.ToString();
            }

            FacebookResponse response = request.InvokeMethod("photos.getAlbums");
            if (response.Status == FacebookResponseStatus.Succeeded) {
                List<Album> albums;

                if (response.Result is ArrayList) {
                    ArrayList albumListState = (ArrayList)response.Result;

                    albums = new List<Album>(albumListState.Count);
                    foreach (Hashtable albumState in albumListState) {
                        albums.Add(new Album(albumState));
                    }
                }
                else if (response.Result is Hashtable) {
                    albums = new List<Album>(1);
                    albums.Add(new Album((Hashtable)response.Result));
                }
                else {
                    albums = new List<Album>(0);
                }

                return albums;
            }

            return null;
        }

        /// <summary>
        /// Gets the list of albums created by the specified user.
        /// </summary>
        /// <param name="userID">The unique ID of the user.</param>
        /// <returns>The list of matching albums.</returns>
        public ICollection<Album> GetAlbumsOfUser(string userID) {
            if (String.IsNullOrEmpty(userID)) {
                throw new ArgumentNullException("userID");
            }

            return GetAlbums(userID, null);
        }

        /// <summary>
        /// Gets the photo identified by its ID.
        /// </summary>
        /// <param name="photoID">The unique ID of the photo.</param>
        /// <returns>The photo information for the specified photo.</returns>
        public Photo GetPhoto(string photoID) {
            if (String.IsNullOrEmpty("photoID")) {
                throw new ArgumentNullException("photoID");
            }

            ICollection<Photo> photos = GetPhotos(null, null, new string[] { photoID });
            if ((photos != null) && (photos.Count != 0)) {
                foreach (Photo photo in photos) {
                    return photo;
                }
            }

            return null;
        }

        /// <summary>
        /// Gets the photos belonging to the specified album.
        /// </summary>
        /// <param name="albumID">The unique ID of the album.</param>
        /// <returns>The list of photos contained within the album.</returns>
        public ICollection<Photo> GetPhotos(string albumID) {
            if (String.IsNullOrEmpty(albumID)) {
                throw new ArgumentNullException("albumID");
            }

            return GetPhotos(null, albumID, null);
        }

        /// <summary>
        /// Gets the list of the specified photos.
        /// </summary>
        /// <param name="photoIDs">The unique IDs of the photos.</param>
        /// <returns>The list of identified photos.</returns>
        public ICollection<Photo> GetPhotos(ICollection<string> photoIDs) {
            if ((photoIDs == null) || (photoIDs.Count == 0)) {
                throw new ArgumentNullException("photoIDs");
            }

            return GetPhotos(null, null, photoIDs);
        }

        private ICollection<Photo> GetPhotos(string userID, string albumID, ICollection<string> photoIDs) {
            FacebookRequest request = new FacebookRequest(_session);
            if (String.IsNullOrEmpty(userID) == false) {
                request.Parameters["subj_id"] = userID;
            }
            if (String.IsNullOrEmpty(albumID) == false) {
                request.Parameters["aid"] = albumID;
            }
            if ((photoIDs != null) && (photoIDs.Count != 0)) {
                StringBuilder idListBuilder = new StringBuilder();
                foreach (string id in photoIDs) {
                    if (idListBuilder.Length != 0) {
                        idListBuilder.Append(",");
                    }
                    idListBuilder.Append(id);
                }
                request.Parameters["pids"] = idListBuilder.ToString();
            }

            FacebookResponse response = request.InvokeMethod("photos.get");
            if (response.Status == FacebookResponseStatus.Succeeded) {
                List<Photo> photos;

                if (response.Result is ArrayList) {
                    ArrayList photoListState = (ArrayList)response.Result;

                    photos = new List<Photo>(photoListState.Count);
                    foreach (Hashtable photoState in photoListState) {
                        photos.Add(new Photo(photoState));
                    }
                }
                else if (response.Result is Hashtable) {
                    photos = new List<Photo>(1);
                    photos.Add(new Photo((Hashtable)response.Result));
                }
                else {
                    photos = new List<Photo>(0);
                }

                return photos;
            }

            return null;
        }

        /// <summary>
        /// Gets the list of photos tagged with the specified user.
        /// </summary>
        /// <param name="userID">The unique ID of the user.</param>
        /// <returns>The list of matching photos.</returns>
        public ICollection<Photo> GetPhotosOfUser(string userID) {
            if (String.IsNullOrEmpty(userID)) {
                throw new ArgumentNullException("userID");
            }

            return GetPhotos(userID, null, null);
        }

        /// <summary>
        /// Uploads a photo contained within the specified stream.
        /// </summary>
        /// <param name="name">The file name of the photo.</param>
        /// <param name="photoStream">The stream containing the data.</param>
        /// <param name="contentType">The content type of the photo.</param>
        /// <param name="caption">The optional caption of the photo.</param>
        /// <param name="albumID">The optional album ID that should contain the photo.</param>
        /// <returns>The information about the uploaded photo.</returns>
        public Photo UploadPhoto(string name, Stream photoStream, string contentType, string caption, string albumID) {
            if (String.IsNullOrEmpty(name)) {
                throw new ArgumentNullException("name");
            }
            if (photoStream == null) {
                throw new ArgumentNullException("photoStream");
            }
            if (String.IsNullOrEmpty(contentType)) {
                throw new ArgumentNullException("contentType");
            }

            FacebookRequest request = new FacebookRequest(_session);
            if (String.IsNullOrEmpty(caption) == false) {
                request.Parameters["caption"] = caption;
            }
            if (String.IsNullOrEmpty(albumID) == false) {
                request.Parameters["aid"] = albumID;
            }
            request.Parameters.SetBlobParameter(name, photoStream, contentType);

            FacebookResponse response = request.InvokeMethod("photos.upload");
            if (response.Status == FacebookResponseStatus.Succeeded) {
                Debug.Assert(response.Result is Hashtable);

                return new Photo((Hashtable)response.Result);
            }

            return null;
        }
    }
}
